"""
This is the network server that provides a tradezone.HTTPClient object to the
client application.

The server is in "multiplex" mode, meaning that method calls are processed
sequentially.
"""


import Pyro4
from system import tradezone
from misc import misc
import logging
from system import threads
import os
import time
import threading


class TZServer(threads.ServerThread):
    """
    Starts a Pyro4 daemon to serve a trazedone.HTTPClient in a thread

    The server is in "multiplex" mode, meaning that method calls are processed
    sequentially.
    
    References:
      http://stackoverflow.com/questions/8508112/requestlooploopcondition-doesnt-release-even-after-loopcondition-is-false
    """
    
    # IP Address
    host = "999.999.999.999"
    
    def __init__(self):
        threads.ServerThread.__init__(self, name="TZ Server")
        self.oHTTP = None
        self.oStreamer = None


    def run_(self):
        self.logger.debug(">>>> TZServer.run_(): BEGIN")
        
        Pyro4.config.SERVERTYPE = "thread" # "multiplex"
        #  "We need to set either a socket communication timeout,
        #   or use the select based server. Otherwise the daemon requestLoop
        #   will block indefinitely and is never able to evaluate the loopCondition.
        #  " -- http://stackoverflow.com/questions/8508112/requestlooploopcondition-doesnt-release-even-after-loopcondition-is-false
        Pyro4.config.COMMTIMEOUT=60.5
        

        oHTTP = tradezone.HTTPClient()
###############        oHTTP.streamer = oStreamer
        self.oHTTP = oHTTP
        self.Login()
        self.logger.info("TZClient Logged in successfully")

        oStreamer = tradezone.Streamer()
        oStreamer.tz = oHTTP
        self.oStreamer = oStreamer
        oStreamer.Start()
        self.logger.info("Streamer started successfully")
        

        # make a Pyro daemon
        self.pyroDaemon = Pyro4.Daemon(host=self.host)
        # find the name server
        self.logger.info("Locating the name server...")
        ns = Pyro4.locateNS()
        self.logger.info("Located.")
        # register the custom object as a Pyro object
        uri = self.pyroDaemon.register(oHTTP)
        # register the object with a name in the name server
        ns.register("tradezone.HTTPClient", uri)
        uri = self.pyroDaemon.register(oStreamer)
        ns.register("tradezone.Streamer", uri)
        
        self.SetStarted()
        
        # start the event loop of the server to wait for calls
        self.flagKeepRunning = True
        self.pyroDaemon.requestLoop(loopCondition=self.GetKeepRunning)
        self.logger.info("Pyro Daemon has stopped")
        
        self.logger.info("Now will exit Streamer")
        oStreamer.exit()
        oStreamer.join()
        self.logger.info("Exited Streamer")
        
        self.logger.debug("<<<< TZServer.run_(): END")
        
    def GetKeepRunning(self):
        return self.flagKeepRunning
        
    def _Exit(self):
        self.flagKeepRunning = False
        self.logger.debug("Told TZ server to Close")
        
    def Login(self):
        """Directly calls oHHTP.Login() trying for 30 seconds."""
        tic = time.time()
        flagOk = False
        T = 30
        while tic-time.time() < T:
            try:
                self.oHTTP.Login()
                flagOk = True
                self.logger.info("Logged into TZDC successfully")
                break
            except:
                self.logger.exception("Login failed")
        if not flagOk:
            self.logger.critical("Failed logging after trying for %d seconds" % T)

def Kill():
    os.system("taskkill /f /im tzdc.exe")

tzdc = None
def StartTZDC():
    Kill()
    global tzdc
    if tzdc:
        tzdc.join()
    tzdc = TZDCThread()
    tzdc.start()

def Menu2():
    return """0 - Exit
1 - Restart TZ Data Center and attempt re-login
3 - Attempt re-login
9 - Print this menu"""


class TZDCThread(threading.Thread):
    """Thread for TZDC because it is blocking."""

    def run(self):
        os.system("tzdc.exe")

if __name__ == "__main__":
    host = misc.AskUser()
    
    flagExit = False
    while not flagExit:
        print """Options now:
0 - Exit
1 - Start/Restart TZ Data Center
2 - Start Navala TZ server and go to next menu
9 - Print available options once started"""
        k = raw_input("? ")
        if k == "1":
            StartTZDC()
        elif k == "2":
            flagStarted = False
            try:
                server = TZServer()
                server.host = host
                server.Start()
                flagStarted = True
            except Exception as E:
                # Unsucessful start, goes back to menu1
                logging.exception(E)
                
            if flagStarted:
                flagExit2 = False
                while not flagExit2:
                    print "Options now:"
                    print Menu2()
                    m = raw_input("")
                    if m == "1":
                        StartTZDC()
                        server.Login()
                    elif m == "3":
                        server.Login()
                    elif m == "9":
                        print Menu2()
                    elif m == "0":
                        flagExit = True
                        flagExit2 = True
        elif k == "9":
            print "Options available once server started:"
            print Menu2()
            print "-----don't confuse-----"
        elif k == "0":
            flagExit = True
            
    if tzdc and tzdc.isAlive():
        Kill()
        tzdc.join()
    
